--
-- GB Radial Menu
-- Adds a radial menu for easier tool-access
-- Version 2008-10-30
--   First internal release
-- Version 2008-11-01
--   Moved tools to a separate config file, so they are preserved in case of script upgrade
--   Added GUI for editing which tools are in the radial menu (HOLY "#/& it took longer than projected!)
-- Version 2008-11-02
--   Apparently it is a REALLY bad idea to manipulate the array you are enumerating .. humdedum, major load bug fixed
--   Renamed RCon to Con, don't know why I chose RCon to begin with :)
--   You can now select if labels should be the same size (the size of the longest), or individually sized. (Actually spared a lot of calculations in the draw routine)
--   A traceline can be drawn from screen-center to mouse cursor when selecting tools
--

if CLIENT then
	-- Variables used globally
	radialConfig = {}										-- Config object
	radialConfigTools = {}							-- Config object - Tools
	local radialMenuShown = false				-- Is the menu visible?
	local screenCenterX = ScrW() / 2		-- X center
	local screenCenterY = ScrH() / 2		-- Y center
	local pi = 4 * math.atan2(1, 1)			-- Pi (Yum :)
	local radialEntrySize = 0						-- How many degrees does a menu entry span?
	local radialMenuSelectedTool = 0		-- The currently selected tool
	local radialVersion = "2008-11-02"	-- Used for config file checking

	-- Include Options menu LUA
	include("gb-radial-options.lua")
	include("gb-radial-utils.lua")

	-- Config Setup, check for an existing config
	if file.Exists("gb-radial-config.txt") and file.Exists("gb-radial-config-tools.txt") then
		-- Config files exists, read and parse
		local configFile = file.Read("gb-radial-config.txt")

		-- Check that we read something, and that there's actually data in our variable
		if (configFile and #configFile > 0) then
			radialConfig = util.KeyValuesToTable(configFile)

			-- Version Check, if its a new version, reset the config var so we use the default instead
			if radialConfig["gbr-version"] ~= radialVersion then
				radialConfig = {}
			end
		end

		-- Tools
		configFile = file.Read("gb-radial-config-tools.txt")

		if (configFile and #configFile > 0) then
			radialConfigTools = util.KeyValuesToTable(configFile)
			
			-- Seems like numeric type information is lost when saving tables using KeyValuesToTable
			--   Writing a new table-saver could be an exercise later?
			local tempToolTable = {}

			for k,v in pairs(radialConfigTools) do				
				if (type(k) ~= "number") then
					-- Convert key value from string to numeric
					tempToolTable[tonumber(k)] = v
				else
					tempToolTable[k] = v
				end
			end
			
			radialConfigTools = tempToolTable
			tempToolTable = nil
		end
	end
	
	-- Check if we read and parsed the config, and if not, create a default valued one
	if table.Count(radialConfig) == 0 then
		-- Default Config
		radialConfig["gbr-version"] = radialVersion						-- Used for config file checking
		radialConfig["gbr-menudeadzone"] = 40									-- Defines the "dead area" around the screen center, where you can't select anything
		radialConfig["gbr-menufont"] = "DefaultLarge"					-- Font used to print the radial menu
		radialConfig["gbr-menusplitterlength"] = 60						-- The lenght of the split-lines between menu items
		radialConfig["gbr-menushowsplitters"] = 1							-- Show or don't show the menu splitter lines
		radialConfig["gbr-menulabelssizedindividually"] = 1		-- Should all tool labels be the same size or not?
		radialConfig["gbr-menushowtraceline"] = 0							-- Draw a line from center screen to mouse cursor?
		
		-- Save config
		saveConfig()

		-- Default Tools, only set these if they haven't been loaded before
		if table.Count(radialConfigTools) == 0 then
			radialConfigTools[1] = { name = "Aimbot Menu", rconcommand = "gzfaimbot_menu" }
			radialConfigTools[2] = { name = "Visual's Menu", rconcommand = "gzfchams_menu" }
			radialConfigTools[3] = { name = "Esp/Radar Menu", rconcommand = "gzfespmenu" }
			radialConfigTools[4] = { name = "SeeAll", rconcommand = "showinvis" }
			radialConfigTools[5] = { name = "Roleplay Wallhack", rconcommand = "gzfrp_wallhack" }
	
			-- Save the tool setup
			saveTools()
		end
	end

	-- Calculate positions for the various radial menu entries
	function CalculateMenuLayout()
		local angle = 0				-- Our starting angle
		local longestName = 0	-- The length of the longest name, used to calculate x/y position
		radialEntrySize = math.floor(360 / table.getn(radialConfigTools))

		-- Find the pixelsize of the largest word, to get an even circle
		for key,value in pairs(radialConfigTools) do
			-- Is this the longest name yet?
			surface.SetFont(tostring(radialConfig["gbr-menufont"]))
			tw, th = surface.GetTextSize(value.name)
			
			if tw > longestName then longestName = tw end
		end

		-- Loop through all tools, and calculate span-angle, x/y position and menu-splitter
		for key,value in pairs(radialConfigTools) do
			value.minangle = angle - (radialEntrySize / 2)
			if value.minangle < 0 then value.minangle = 360 + value.minangle end	-- First tool MinAngle will always dip below 0, and have to "wrap" down from 360

			value.maxangle = angle + (radialEntrySize / 2)

			value.xpos = screenCenterX - ((radialConfig["gbr-menudeadzone"] + (longestName / 2)) * math.sin((360 - angle) * (pi / 180)))	-- X position of the menu point text
			value.ypos = screenCenterY - ((radialConfig["gbr-menudeadzone"] + (longestName / 2)) * math.cos((360 - angle) * (pi / 180)))	-- Y position of the menu point text

			value.menusplitxinner = screenCenterX - (radialConfig["gbr-menudeadzone"] * math.sin((360 - value.minangle) * (pi / 180)))	-- Used to draw a split-line from center-screen, 100 pixels out
			value.menusplityinner = screenCenterY - (radialConfig["gbr-menudeadzone"] * math.cos((360 - value.minangle) * (pi / 180)))	-- -O-
			value.menusplitxouter = screenCenterX - ((radialConfig["gbr-menusplitterlength"] + radialConfig["gbr-menudeadzone"]) * math.sin((360 - value.minangle) * (pi / 180)))	-- -O-
			value.menusplityouter = screenCenterY - ((radialConfig["gbr-menusplitterlength"] + radialConfig["gbr-menudeadzone"]) * math.cos((360 - value.minangle) * (pi / 180)))	-- -O-

			-- Should labels be the same size or not?
			tw, th = surface.GetTextSize(value.name)
			
			if radialConfig["gbr-menulabelssizedindividually"] == 1 then
				-- Labels are individually sized
				value.labelwidth = tw
				value.labelheight = th
			else
				-- Labels are same size (ie, size of the longest name)
				value.labelwidth = longestName
				value.labelheight = th
			end

			-- Increase the angle
			angle = angle + radialEntrySize
		end
		
		-- Set the last entrys max to the first entrys min, so we don't get any "empty" menu-space
		radialConfigTools[table.getn(radialConfigTools)].maxangle = radialConfigTools[1].minangle
	end

	-- Calculate the menu layout
	CalculateMenuLayout()

	-- Functions to show and hide the menu
	function ShowRadialMenu()
		-- Enable mouse cursor
		gui.EnableScreenClicker(true)
		
		-- Set cursor centerscreen
		gui.SetMousePos(screenCenterX, screenCenterY)
		
		-- Show menu
		radialMenuShown = true		
	end

	function HideRadialMenu()
		-- Is there an active tool?
		if radialMenuSelectedTool > 0 then
			-- Yes there is, select the tool
			LocalPlayer():ConCommand(radialConfigTools[radialMenuSelectedTool].rconcommand)
			
			-- Now we dont have a selected tool
			radialMenuSelectedTool = 0
		end
		
		-- Disable mouse cursor
		gui.EnableScreenClicker(false)

		-- Hide menu
		radialMenuShown = false
	end
	
	-- Print text in a RoundedBox, centered at required coordinates, using given color
	function DrawRadialMenuItem(itemText, itemXpos, itemYpos, labelWidth, labelHeight, boxColor, textColor)
		if not itemText then return end
		
		-- Draw the roundedbox
		draw.RoundedBox(8, (itemXpos - (labelWidth / 2) - 5), (itemYpos - (labelHeight / 2) - 2), labelWidth + 10, labelHeight + 4, boxColor)
		
		-- Draw the text
		draw.SimpleText(itemText, radialMenuFont, itemXpos, itemYpos, textColor, 1, 1)
	end
	
	function DrawRadialMenu()
		-- Do not draw the menu if it is not shown
		if not radialMenuShown then return end
		
		-- Draw a line from screen-center to mouse cursor, if enabled
		if radialConfig["gbr-menushowtraceline"] == 1 then
			surface.SetDrawColor(255, 255, 255, 80)
			surface.DrawLine(screenCenterX, screenCenterY, gui.MouseX(), gui.MouseY())					
		end
		
		-- Is the distance from screen-center to the cursor larger than the set deadspace?
		if math.Dist(screenCenterX, screenCenterY, gui.MouseX(), gui.MouseY()) > radialConfig["gbr-menudeadzone"] then
			-- We have moved out of the deadzone
			-- Calculate the angle from screen-center to the mousecursor, so we can determine which radial element the cursor is over
			local radialSelectAngle = 360 - (math.Rad2Deg(math.atan2(gui.MouseX() - screenCenterX, gui.MouseY() - screenCenterY)) + 180)	-- Manipulate the degrees, so we get 0 to be upwards, and increasing clockwise

			-- Loop tools them and find out which one is active
			for key,value in pairs(radialConfigTools) do
				-- Check for a "normal" entry first (one that doesn't span 0)
				if (value.minangle <= radialSelectAngle) and (value.maxangle > radialSelectAngle) then
					-- We have found the active tool
					radialMenuSelectedTool = key
					
					-- Break out of the for loop
					break
				end

				if value.minangle > value.maxangle then
					-- MinAngle is larger than MaxAngle, we have the entry that spans 0 degrees (straight up)
					if (value.minangle <= radialSelectAngle) or (value.maxangle > radialSelectAngle) then
						-- We have found the active tool
						radialMenuSelectedTool = key

						-- Break out of the for loop
						break
					end
				end
			end			
		else
			-- We are in the deadzone, no tools are selected
			radialMenuSelectedTool = 0
		end
		
		-- Draw the tool menu entries
		for key,value in pairs(radialConfigTools) do
			if key == radialMenuSelectedTool then
				-- This is the selected tool
				DrawRadialMenuItem(value.name, value.xpos, value.ypos, value.labelwidth, value.labelheight, Color(5, 26, 48, 255), Color(221, 16, 16, 255))
			else
				-- This is not the selected tool
				DrawRadialMenuItem(value.name, value.xpos, value.ypos, value.labelwidth, value.labelheight, Color(5, 26, 48, 255), Color(255, 255, 255, 255))
			end
			
			-- Draw the splitter-line, if the user wants to
			if radialConfig["gbr-menushowsplitters"] == 1 then
				surface.SetDrawColor(255, 255, 255, 80)
				surface.DrawLine(value.menusplitxinner, value.menusplityinner, value.menusplitxouter, value.menusplityouter)			
			end
		end				
	end

	-- Add hook to paint the radial menu
	hook.Add("HUDPaint", "DrawRadialMenu", DrawRadialMenu)
	
	-- Capture both left and right-click (to override left, and open settings menu on right
	function CaptureMouseClicks(mouseInfo)
		-- Do not do any of this if the menu is not shown
		if not radialMenuShown then return end
		
		-- Handle different clicktypes
		if mouseInfo == 107 then
			-- Left click, just make it impossible to left-click
			return true
		elseif mouseInfo == 108 then
			-- Right click, open the config menu
			openRadialMenuConfig()
			
			return true
		end
	end
	hook.Add("GUIMousePressed", "CaptureMouseClicks", CaptureMouseClicks)
		
	
	-- Add con commands to show/hide the menu
	concommand.Add("+gzffastmenu", ShowRadialMenu)
	concommand.Add("-gzffastmenu", HideRadialMenu)
end